/**
 * 通过 pv 操作， 父进程往文件写入数据，
 * 子进程从文件读出数据并显示，交替执行 
*/

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semid_write;
int semid_read;

#define PERM S_IRUSR | S_IWUSR | IPC_CREAT

union semun {
    int val;
    struct semid_ds *buf;
    ushort *array;
};

void init_sem(void)
{
    semid_read = semget((key_t)1024, 1, PERM);
    semid_write = semget((key_t)2048, 1, PERM);

    union semun semun;
    semun.val = 0;

    semctl(semid_read, 0, SETVAL, semun);
    semctl(semid_write, 0, SETVAL, semun);
}

void semaphore_p(int semid)
{
    struct sembuf sembuf = {0, -1, SEM_UNDO};
    semop(semid, &sembuf, 1);
}

void semaphore_v(int semid)
{
    struct sembuf sembuf = {0, 1, SEM_UNDO};
    semop(semid, &sembuf, 1);
}

void destory_sem(void)
{
    semctl(semid_write, 0, IPC_RMID);
    semctl(semid_read, 0, IPC_RMID);
}

int main()
{
    init_sem();

    int fd = open("share_file.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if (0 > fd)
    {
        perror("open error： ");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (0 > pid)
    {
        perror("fork error: ");
        exit(EXIT_FAILURE);
    }
    else if (0 == pid)
    {
        char buf[1024];

        int i = 0;
        for (; i < 100; ++i)
        {
            memset(buf, 0, 1024);
            semaphore_p(semid_read);

            lseek(fd, 0, SEEK_SET);
            if (read(fd, buf, 1024) < 0)
            {
                perror("read error: ");
                exit(EXIT_FAILURE);
            }
            printf("pid(%u) , read value = %s\n", getpid(), buf);
            semaphore_v(semid_write);
        }
    }
    else
    {
        char buf[1024];

        int i = 0;
        for (; i < 100; ++i)
        {
            snprintf(buf, 1024, "Hello %d", i);

            lseek(fd, 0, SEEK_SET);
            if (write(fd, buf, strlen(buf)) < 0)
            {
                perror("write error: ");
                exit(EXIT_FAILURE);
            }
            printf("pid(%u) , write value = %s\n", getpid(), buf);

            semaphore_v(semid_read);
            semaphore_p(semid_write);
        }
    }

    destory_sem();

    return 0;
}